(function(){ /** START SHOPIFY ADD TO CART **/ let isPageReloadRequired = false; let statusPromise, productEndpoint; class DoofinderAddToCartError extends Error { constructor(reason, status = "") { const message = "Error adding an item to the cart. Reason: " + reason + ". Status code: " + status; super(message); this.name = "DoofinderAddToCartError"; } } document.addEventListener('doofinder.cart.add', function(event) { statusPromise = event.detail.statusPromise; productEndpoint = new URL(event.detail.link).pathname + '.js'; fetch(productEndpoint, { method: 'GET', headers: { 'Content-Type': 'application/json' }, }) .then(response => { return response.json(); }) .then(data => { const variantId = getVariantId(parseInt(event.detail.item_id), data) if (variantId) { addToCart(variantId, event.detail.amount) } else { statusPromise.reject(new DoofinderAddToCartError("Variant not found, redirecting to the item page", 200)); window.location.href = event.detail.link } }) .catch((error) => { console.error('Error:', error) statusPromise.reject(new DoofinderAddToCartError(error, 400)); }); }); function getVariantId(productId, productData) { if (productData.variants.length > 1) { if (isVariantIdInList(productId, productData.variants)) { return productId; } return false; } else { return productData.variants[0].id; } } function isVariantIdInList(variantId, variantList) { let isVariant = false; variantList.forEach(variant => { if (variant.id === variantId) { isVariant = true; } }) return isVariant; } function addToCart(id, amount) { let blockData = getBlockDataFromTheme(); let formData = { 'items': [{ 'id': id, 'quantity': amount }], sections: blockData.sections }; const route = getShopifyCartPath() + '/add.js' ; fetch(route, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formData) }) .then(response => response.json()) .then(data => { statusPromise.resolve("The item has been successfully added to the cart."); updateCartContentsByTheme(data, blockData.cartSectionData); }) .catch((error) => { console.error('Error:', error); statusPromise.reject(new DoofinderAddToCartError(error, 400)); }); } function updateCartContentsByTheme(data, cartSectionData) { const themeName = getNormalizedThemeName(); switch (themeName) { case 'debutify': window.theme?.ajaxCart?.update(); break; case 'prestige': document.dispatchEvent(new CustomEvent("cart:refresh")); setReloadRequiredOnMainCartPage(); break; case 'impulse': document.dispatchEvent(new CustomEvent('cart:build')); setReloadRequiredOnMainCartPage(); break; case 'motion': document.dispatchEvent(new CustomEvent('cart:build')); break; case 'turbo': isPageReloadRequired = true; break; case 'expanse': document.dispatchEvent(new CustomEvent('ajaxProduct:added', { detail: {product: data} })); setReloadRequiredOnMainCartPage(); break; case 'split': updateCartInSplitTheme(data); setReloadRequiredOnMainCartPage(); break; case 'warehouse': updateCartInWarehouseTheme(); setReloadRequiredOnMainCartPage(); break; case 'impact': document.dispatchEvent(new CustomEvent('cart:refresh')); setReloadRequiredOnMainCartPage(); break; case 'pipeline': document.dispatchEvent(new CustomEvent('theme:cart:init')); document.dispatchEvent(new CustomEvent('theme:cart:reload')); break; default: renderSections(data.sections, cartSectionData); break; } } function updateCartInSplitTheme(data) { const productCountNode = document.querySelector('.cart-menu .count-holder .count'); if (null !== productCountNode) { const productCount = parseInt(productCountNode.textContent) + 1; productCountNode.innerHTML = productCount; let item = data.items[0]; item.dataset = ''; document.querySelector('cart-form')?.updateCartQty(data.items[0], data.items[0].quantity); } } function updateCartInWarehouseTheme() { const cartSelector = document.querySelector(".header__action-item--cart"); if (null !== cartSelector && 'function' === typeof Cart) { const cart = new Cart(cartSelector, {}); cart._rerender(false); } } function renderSections(sections, cartSectionData){ let isAnySectionUpdatedProperly = false; if (null === sections) { return; } for (let sectionId in sections){ if (null === sections[sectionId]) { continue; } const section = sections[sectionId]; const domParser = new DOMParser(); const sectionHtmlDOM = domParser.parseFromString(section, 'text/html'); const sectionSelector = getHtmlSelectorByTheme(sectionId, sectionHtmlDOM); if ('' === sectionSelector) { continue; } let sectionHTMLFromShopify = document.querySelector(sectionSelector); if (null === sectionHTMLFromShopify) { // Fallback using the section ID sectionHTMLFromShopify = document.querySelector('#' + sectionId); } if (isCartPage()) { if (Object.hasOwn(cartSectionData, 'forceReload') && cartSectionData.forceReload) { isPageReloadRequired = true; return; } if (cartSectionData.name === sectionId) { maybeInjectMainCartList(section, cartSectionData); } } if (sectionHTMLFromShopify) { isAnySectionUpdatedProperly = true; sectionHTMLFromShopify.innerHTML = section; } } // Last resort if all the sections come as null if (!isAnySectionUpdatedProperly) { isPageReloadRequired = true; } } function maybeInjectMainCartList(section, cartSectionData) { if ('' === cartSectionData.cartArea) { return; } const emptyCart = document.querySelector(cartSectionData.cartArea); if (null === emptyCart) { return; } if ('' !== cartSectionData.visibilityClass) { emptyCart.classList.remove(cartSectionData.visibilityClass); return; } const cartForm = emptyCart.querySelector('form'); if (null !== cartForm) { return; } const formDom = document.createElement('form'); formDom.setAttribute('action', getShopifyCartPath()); formDom.setAttribute('method', 'post'); formDom.setAttribute('id', 'cart'); formDom.innerHTML = section; emptyCart.innerHTML = formDom; } function getShopifyCartPath() { return Shopify.routes.root ? Shopify.routes.root + 'cart' : Shopify.routes.cart_url; } function getHtmlSelectorByTheme(sectionId, htmlNode) { const themeName = getNormalizedThemeName(); let selector = ''; switch (themeName) { case 'debutify': selector = '[data-section-type="' + sectionId + '"]'; break; case 'district': selector = '.section__header-top'; break; case 'split': selector = '.site-nav-container-last'; break; default: selector = getGenericHtmlSelector(htmlNode); break; } return selector; } function getGenericHtmlSelector(htmlNode) { const element = htmlNode.body.firstChild; let selector = ''; if ('undefined' !== typeof element.id) { selector += '#' + element.id; } else if (element.classList.length > 0) { selector += '.' + element.classList.join(",."); // Additional selector by data attributes if (element.dataset.length > 0) { for (let key in element.dataset) { selector += '[data-' + key + '="' + element.dataset[key] + '"]'; } } } if ('' !== selector) { selector = element.tagName.toLowerCase() + selector; } return selector; } function getBlockDataFromTheme() { let blocks = {sections:'cart-items,cart-icon-bubble,cart-live-region-text,cart-footer', cartSectionData: {}}; try { const themeName = getNormalizedThemeName(); switch (themeName) { case 'dawn': blocks.sections = 'cart-icon-bubble,main-cart-items'; blocks.cartSectionData = {name: 'main-cart-items', cartArea: 'cart-items.is-empty', visibilityClass: 'is-empty'}; break; case 'showtime': blocks.sections = 'header'; blocks.cartSectionData = {}; break; case 'debut': blocks.sections = 'header,cart-template'; blocks.cartSectionData = {name: 'cart-template', cartArea: '', visibilityClass: ''}; break; case 'district': blocks.sections = 'header-top'; blocks.cartSectionData = {forceReload: true}; break; case 'split': blocks.sections = 'helper-cart'; blocks.cartSectionData = {}; break; case 'expanse': blocks.sections = 'cart-ajax'; blocks.cartSectionData = {}; break; } } catch(e) { console.warn('[DOOFINDER] The name of the theme could not be detected. Applying default sections to refresh the cart drawer'); } return blocks; } function getNormalizedThemeName() { return Shopify.theme.schema_name.toLowerCase(); } function isCartPage() { return getShopifyCartPath() === window.location.pathname; } function setReloadRequiredOnMainCartPage() { if (isCartPage()) { isPageReloadRequired = true; } } document.addEventListener('doofinder.hide', function(event) { if ('undefined' !== typeof isPageReloadRequired && isPageReloadRequired) { window.location.reload(); return; } }); document.addEventListener('doofinder.show', function(event) { const themeName = getNormalizedThemeName(); switch (themeName) { case 'district': document.querySelector('.predictive__overlay').click(); break; case 'motion': document.dispatchEvent(new CustomEvent('predictive-search:close')); break; case 'split': document.querySelector('#site-overlay').click(); break; case 'impact': document.querySelector('search-drawer')?.hide(); break; } }); /** END SHOPIFY ADD TO CART **/ })();